using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using OWED.Network;
using OWED.Network.Messages;
using OWED.Network.Messages.General;
using OWED.Network.Messages.Reply;

using System.Xml;

using OWED.Document;

namespace ClientGUI
{
    /// <summary>
    /// This is the main window
    /// </summary>
    public partial class MainForm : Form
    {
        String my_current_filename;
        Main.ProgramData my_data;
        /// <summary>
        /// Do you know the muffin man?
        /// </summary>
        public MainForm()
        {
            my_current_filename = null;
            InitializeComponent();

            my_data = new ClientGUI.Main.ProgramData();
            ToolStripItemCollection items = networkToolStripMenuItem.DropDown.Items;
            foreach (ToolStripItem item in items)
            {
                item.Enabled = false;
            }
            connectToolStripMenuItem.Enabled = true;

            XmlDocument config = new XmlDocument();
            config.LoadXml(global::ClientGUI.Config.Configuration_xml);
            ProgramData.Config = new Configuration(config);
            doc_editor.Config = ProgramData.Config;
        }

        /// <summary>
        /// Happens when a connection excepts (throws an exception), this is called.
        /// </summary>
        /// <param name="exc"></param>
        public void ConnectionExceptionHandle(ConnectionException exc)
        {
            StatusMessage(exc.Message);
            disable_remote_menu();
        }


        private delegate void EnableDelegate();
        /// <summary>
        /// Enables use of all the items under the "Network" menu.
        /// </summary>
        private void enable_remote_menu()
        {
            if (InvokeRequired)
            {
                EnableDelegate d = new EnableDelegate(enable_remote_menu);
                Invoke(d);
            }
            ToolStripItemCollection items = networkToolStripMenuItem.DropDown.Items;
            foreach (ToolStripItem item in items)
            {
                item.Enabled = true;
            }
        }

        private delegate void DisableDelegate();
        /// <summary>
        /// Enables use of all the items under the "Network" menu.
        /// </summary>
        private void disable_remote_menu()
        {
            if (InvokeRequired)
            {
                DisableDelegate d = new DisableDelegate(disable_remote_menu);
                Invoke(d);
            }
            ToolStripItemCollection items = networkToolStripMenuItem.DropDown.Items;
            foreach (ToolStripItem item in items)
            {
                item.Enabled = false;
            }
            connectToolStripMenuItem.Enabled = true;
        }

        /// <summary>
        /// Sets doc as the document displayed/edited by this window.
        /// </summary>
        /// <param name="doc">your document</param>
        public void SetDocument(XmlDocument doc)
        {
            //doc.FirstChild.FirstChild.FirstChild;
            doc_editor.SetDocument(doc);
        }

        /// <summary>
        /// Get the document that this editor represents.
        /// </summary>
        /// <returns></returns>
        public XmlDocument GetDocument()
        {
            return doc_editor.GetDocument();
        }

        /// <summary>
        /// Sets whether or not this window is connected.
        /// This has a side effect of making the menu items under Network work.
        /// </summary>
        public bool Connected
        {
            set
            {
                if (value)
                    enable_remote_menu();
                else
                    disable_remote_menu();
            }
        }

        /// <summary>
        /// Safely quits the application.
        /// </summary>
        public void Quit()
        {
            Dispose();
        }

        /// <summary>
        /// Various global data for this window and all of its children.
        /// </summary>
        public Main.ProgramData ProgramData
        {
            get
            {
                return my_data;
            }
        }

        private void connectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Main.PopUpWindows.LoginForm(this).Show();
        }

        private void getDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Main.PopUpWindows.GetDocument(this); //will show itself.
            //it may have to dispose itself...
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            doc_editor.Width = Width;
            doc_editor.Height = Height - (menuStrip1.Height + 
                                            status_lbl.Height + 
                                            statusStrip1.Height + 
                                            15);
            //I can't figure out why this needs the extra constant, but oh well
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Quit();
        }

        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Connected = false;
            ProgramData.Connection.Dispose();
            ProgramData.Connection = null;
            disable_remote_menu();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog diag = new OpenFileDialog();
            DialogResult res = diag.ShowDialog();
            if (res.Equals(DialogResult.OK)) {
                String filename = diag.FileName;
                String content = System.IO.File.ReadAllText(filename);
                XmlDocument doc = new XmlDocument();
                try
                {
                    doc.LoadXml(content);
                }
                catch (XmlException)
                {
                    Error("This is probably not a valid xml file!");
                }
                SetDocument(doc);
                my_current_filename = filename;
            }
        }



        System.Threading.Timer my_status_timer = null;
        delegate void StatusAway(String msg);
        /// <summary>
        /// Sets the status bar and removes the message after a timeout
        /// </summary>
        /// <param name="message"></param>
        public void StatusMessage(String message)
        {
            if (my_status_timer != null)
            {
                my_status_timer.Dispose();
                my_status_timer = null;
            }
            System.Threading.TimerCallback callback = delegate(object state)
            {
                Invoke(new StatusAway(StatusMessage), "");
                if (my_status_timer != null)
                {
                    my_status_timer.Dispose();
                    my_status_timer = null;
                }
            };
            my_status_timer = new System.Threading.Timer(callback, null, 5000, 1000);
            
            status_lbl.Text = message;
        }

        /// <summary>
        /// Displays the error to the user in a uniform manner.
        /// </summary>
        /// <param name="display_error"></param>
        public void Error(String display_error)
        {
            StatusMessage(display_error);
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Save();
        }

        /// <summary>
        /// Saves the currently opened file.
        /// </summary>
        private void Save()
        {
            if (my_current_filename != null)
            {
                String content = doc_editor.GetDocument().OuterXml;
                System.IO.File.WriteAllText(my_current_filename, content);
                StatusMessage("File saved.");
            }
            else
            {
                Error("No file open right now");
            }
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog diag = new SaveFileDialog();
            DialogResult res = diag.ShowDialog();
            if (res == DialogResult.OK)
            {
                my_current_filename = diag.FileName;
                Save();   
            }
        }

        private void importDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new ClientGUI.Main.PopUpWindows.ImportDocument(this)).Show();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new ClientGUI.Main.PopUpWindows.AboutDiag()).Show();
        }

        private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new ClientGUI.Main.PopUpWindows.Preferences(ProgramData.Config)).Show();
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<book></book>");
            SetDocument(doc);   
        }

        private void deleteSelectedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            doc_editor.RemoveSelected();   
        }

        /// <summary>
        /// Sends a proposal to the backend..
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void proposeToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (ProgramData.Connection == null)
            {
                StatusMessage("Not connected");
                return;
            }
            Console.WriteLine(1);
            if (ProgramData.DocName != null)
            {
                Console.WriteLine(2);
                if (doc_editor.Changes.Count > 0)
                {
                    Console.WriteLine(3);
                    List<Change> ls = new List<Change>();
                    foreach (ChangeAtom ca in doc_editor.Changes)
                    {
                        ls.Add(new Change(new Text(ca.Serialize())));
                    }
                    Console.WriteLine(4);
                    Changes c = new Changes(ls);

                    Console.WriteLine(5);
                    ProposeVersion propose = new ProposeVersion(
                      ProgramData.User, ProgramData.DocName, c);

                    Console.WriteLine(6);
                    XmlDocument re = ProgramData.Connection.Send(propose.ToXml());
                    Console.WriteLine(7);
                    if (re == null)
                    {
                        StatusMessage("Failed for unknown reason");
                        return;
                    }
                    Console.WriteLine(8);
                    IProtocolItem reply = MessageGet.GetFromXml(re);
                    Console.WriteLine(9);
                    if (reply == null)
                    {
                        StatusMessage("Failed for unknown reason");
                        return;
                    }
                    Console.WriteLine(10);
                    PassFail pf = reply as PassFail;
                    if (pf == null)
                    {
                        StatusMessage("Failed for unknown reason");
                        return;
                    }
                    Console.WriteLine(11);
                    if (pf.pass)
                    {
                        StatusMessage("Passed: " + pf.Reason.Value);
                    }
                    else
                    {
                        StatusMessage("Failed: " + pf.Reason.Value);
                    }
                    Console.WriteLine(12);
                }
                else
                {
                    StatusMessage("Nothing to propose");
                }
            }
            else
            {
                StatusMessage("Not currently editing a network file");
            }
            Console.WriteLine(13);
        }

        private void approveProposalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new ClientGUI.Main.PopUpWindows.ApproveProposal(this)).Show();
        }
    }
}